﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NFlickr.Resource;
using NFlickr.Core.Interface;
using System.Net;
using System.IO;

namespace NFlickr.Communication
{

    public class HttpChannel : IChannel
    {
        public event EventHandler<SendRequestCompletedEventArgs> Complete;

        public event SignatureRequiredEventHandler SignatureRequired;

        public IEncyptionProvider EncrptProvider
        {
            get;
            set;
        }

        public IRESTServiceProvider RESTServiceProvider
        {
            get;
            set;
        }

        public string Host { get; set; }
        public int Port { get; set; }
        public bool IsHttps { get; set; }


        public IResult UploadFile(string url, IFlickrService service, string fileFormatName, string fileName, string contentType)
        {
            
            if ((fileFormatName == null) ||
                (fileFormatName.Length == 0))
            {
                fileFormatName = "file";
            }

            if ((contentType == null) ||
                (contentType.Length == 0))
            {
                contentType = "application/octet-stream";
            }

            string queryString = RESTServiceProvider.GetQueryString(service.Params,service.Secret);
            if (service.RequireSigned)
            {
                string encryptedText = EncrptProvider.GetEncrypted(queryString);
                if (SignatureRequired != null)
                {
                    queryString = SignatureRequired(this, new SignatureRequiredEventArgs { Singnature = encryptedText, QueryString = queryString });
                }
            }


            string postdata;
            postdata = "?";
            if (service.Params != null)
            {
                foreach (string key in service.Params.Keys)
                {
                    postdata += key + "=" + service.Params[key] + "&";
                }
            }
            string postUrl = GetUrl(Host, Port, IsHttps, url);

            Uri uri = new Uri(postUrl);


            string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
            HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(uri);
            webrequest.ContentType = "multipart/form-data; boundary=" + boundary;
            webrequest.Method = "POST";


            // Build up the post message header
            StringBuilder sb = new StringBuilder();

            foreach (string key in service.Params.Keys)
            {
                sb.Append("--");
                sb.Append(boundary);
                sb.Append("\r\n");
                sb.AppendFormat("Content-Disposition: form-data; name=\"{0}\"", key);
                sb.Append("\r\n");
                sb.Append("\r\n");
                sb.Append(service.Params[key]);
                sb.Append("\r\n");
            }

            sb.Append("--");
            sb.Append(boundary);
            sb.Append("\r\n");
            sb.Append("Content-Disposition: form-data; name=\"");
            sb.Append(fileFormatName);
            sb.Append("\"; filename=\"");
            sb.Append(Path.GetFileName(fileName));
            sb.Append("\"");
            sb.Append("\r\n");

            sb.Append("Content-Type: ");
            sb.Append(fileName);
            sb.Append("\r\n");
            sb.Append("\r\n");


            string postHeader = sb.ToString();
            byte[] postHeaderBytes = Encoding.UTF8.GetBytes(postHeader);

            // Build the trailing boundary string as a byte array
            // ensuring the boundary appears on a line by itself
            byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

            using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
            {
                long length = postHeaderBytes.Length + fileStream.Length + boundaryBytes.Length;
                webrequest.ContentLength = length;

                using (Stream requestStream = webrequest.GetRequestStream())
                {
                    // Write out our post header
                    requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);

                    // Write out the file contents
                    byte[] buffer = new Byte[checked((uint)Math.Min(4096, (int)fileStream.Length))];
                    int bytesRead = 0;
                    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                        requestStream.Write(buffer, 0, bytesRead);

                    // Write out the trailing boundary
                    requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                    using (WebResponse responce = webrequest.GetResponse())
                    {
                        using (Stream s = responce.GetResponseStream())
                        {
                            using (StreamReader sr = new StreamReader(s))
                            {
                                 string result=sr.ReadToEnd();

                                 IResult returnValue = null;
                                 if (Complete != null)
                                 {
                                     SendRequestCompletedEventArgs args = new SendRequestCompletedEventArgs { Response = result };
                                     Complete(this, args);
                                     returnValue = args.Result;
                                 }
                                 return returnValue;
                            }

                        }

                    }
                }


            }
        }

        public IResult SendRequest(string url, IFlickrService service)
        {
            string queryString = RESTServiceProvider.GetQueryString(service.Params,service.Secret);
            if (service.RequireSigned)
            {
                string encryptedText = EncrptProvider.GetEncrypted(queryString);
                if (SignatureRequired != null)
                {
                    queryString = SignatureRequired(this, new SignatureRequiredEventArgs { Singnature = encryptedText, QueryString = queryString });
                }
            }

            string postUrl = GetUrl(Host, Port, IsHttps, url);
            string result = HttpPost(postUrl, queryString);
            IResult returnValue = null;
            if (Complete != null)
            {
                SendRequestCompletedEventArgs args = new SendRequestCompletedEventArgs { Response = result };
                Complete(this, args);
                returnValue = args.Result;
            }
            return returnValue;
        }

        public string GetUrl(string host, int port, bool isHttps, string url)
        {
            return NFlickr.Helper.Url.GetUrl(host, port, isHttps, url);
        }
        string HttpPost(string uri, string parameters)
        {
            WebRequest webRequest = WebRequest.Create(uri);
            webRequest.ContentType = "application/x-www-form-urlencoded";
            webRequest.Method = "POST";
            byte[] bytes = Encoding.ASCII.GetBytes(parameters);
            Stream os = null;
            try
            {
                webRequest.ContentLength = bytes.Length;
                os = webRequest.GetRequestStream();
                os.Write(bytes, 0, bytes.Length);
            }
            catch (WebException ex)
            {
                return null;
            }
            finally
            {
                if (os != null)
                {
                    os.Close();
                }
            }

            try
            {

                WebResponse webResponse = webRequest.GetResponse();
                if (webResponse == null)
                { return null; }
                using (StreamReader sr = new StreamReader(webResponse.GetResponseStream()))
                {
                    return sr.ReadToEnd().Trim();
                }

            }
            catch (WebException ex)
            {
                return null;
            }
        }
    }
}
